#include "woptions/options.h"
#include "test.h"

namespace {

struct MyCallback
{
	MyCallback(bool *called_) : called(called_) {}

	void operator()(const std::string& opt,  const std::vector<std::string>& args )
	{
		*called = true;
	}
	
	bool *called;
};

struct MyObject
{
	MyObject() : value(0) {}

	void SetValue(int to)
	{
		value = to;
	}

	int value;
};

int gMyFunctionValue = 0;

void MyFunction(int arg)
{
	gMyFunctionValue = arg;
}

} // namespace

BOOST_AUTO_TEST_CASE( test_bind_option_ignore )
{
	woptions::Options opts;
	opts.option("-o","","desc",woptions::bind_option_ignore());
	
	std::vector<std::string> args(1);
	args[0] = "-o";
	
	BOOST_CHECK_NO_THROW( opts.parse(args) );
}

BOOST_AUTO_TEST_CASE( test_bind_option_var )
{
	int         ivalue=0;
	float       fvalue=0;
	std::string svalue="";
	
	woptions::Options opts;
	opts.option("-i","(value)","desc",woptions::bind_option_var(ivalue));
	opts.option("-f","(value)","desc",woptions::bind_option_var(fvalue));
	opts.option("-s","(value)","desc",woptions::bind_option_var(svalue));
	
	std::vector<std::string> args(6);
	args[0] = "-i";
	args[1] = "1";
	args[2] = "-f";
	args[3] = "1.5";
	args[4] = "-s";
	args[5] = "string";
	
	BOOST_CHECK_NO_THROW( opts.parse(args) );
	BOOST_CHECK_EQUAL( ivalue, 1 );
	BOOST_CHECK_EQUAL( fvalue, 1.5f );
	BOOST_CHECK_EQUAL( svalue, "string" );
	
	args[1] = "1.5";
	BOOST_CHECK_THROW( opts.parse(args), woptions::ArgumentException );
}

BOOST_AUTO_TEST_CASE( test_bind_option_var2 )
{
	int val1=0,val2=0;
	
	woptions::Options opts;
	opts.option("-i","(value) (value)","desc",woptions::bind_option_var(val1,val2));
	
	std::vector<std::string> args(3);
	args[0] = "-i";
	args[1] = "1";
	args[2] = "2";
	
	BOOST_CHECK_NO_THROW( opts.parse(args) );
	BOOST_CHECK_EQUAL( val1, 1 );
	BOOST_CHECK_EQUAL( val2, 2 );
}

BOOST_AUTO_TEST_CASE( test_bind_option_var3 )
{
	int val1=0,val2=0,val3=0;
	
	woptions::Options opts;
	opts.option("-i","(value) (value) (value)","desc",woptions::bind_option_var(val1,val2,val3));
	
	std::vector<std::string> args(4);
	args[0] = "-i";
	args[1] = "1";
	args[2] = "2";
	args[3] = "3";
	
	BOOST_CHECK_NO_THROW( opts.parse(args) );
	BOOST_CHECK_EQUAL( val1, 1 );
	BOOST_CHECK_EQUAL( val2, 2 );
	BOOST_CHECK_EQUAL( val3, 3 );
}

BOOST_AUTO_TEST_CASE( test_bind_option_value )
{
	bool flag_set = false;
	
	woptions::Options opts;
	opts.option("-o","","desc",woptions::bind_option_value(flag_set,true));
	
	{
		std::vector<std::string> args;
	
		BOOST_CHECK_NO_THROW( opts.parse(args) );
		BOOST_CHECK_EQUAL( flag_set, false );
	}
	
	{
		std::vector<std::string> args(1);
		args[0] = "-o";
	
		BOOST_CHECK_NO_THROW( opts.parse(args) );
		BOOST_CHECK_EQUAL( flag_set, true );
	}
}

BOOST_AUTO_TEST_CASE( test_bind_option_callback )
{
	bool called = false;
	MyCallback f(&called);

	woptions::Options opts;
	opts.option("-o","","desc",woptions::bind_option_callback(f,0));
	
	{
		std::vector<std::string> args;
	
		BOOST_CHECK_NO_THROW( opts.parse(args) );
		BOOST_CHECK_EQUAL( called, false );
	}
	
	{
		std::vector<std::string> args(1);
		args[0] = "-o";
	
		BOOST_CHECK_NO_THROW( opts.parse(args) );
		BOOST_CHECK_EQUAL( called, true );
	}
}

BOOST_AUTO_TEST_CASE( test_bind_option_mem_callback )
{
	bool called = false;
	MyCallback f(&called);

	woptions::Options opts;
	opts.option("-o","","desc",woptions::bind_option_mem_callback(&f,&MyCallback::operator(),0));
	
	{
		std::vector<std::string> args;
	
		BOOST_CHECK_NO_THROW( opts.parse(args) );
		BOOST_CHECK_EQUAL( called, false );
	}
	
	{
		std::vector<std::string> args(1);
		args[0] = "-o";
	
		BOOST_CHECK_NO_THROW( opts.parse(args) );
		BOOST_CHECK_EQUAL( called, true );
	}
}

BOOST_AUTO_TEST_CASE( test_bind_option_fun )
{
	woptions::Options opts;
	opts.option("-o","(value)","desc",woptions::bind_option_fun(MyFunction));
	
	{
		std::vector<std::string> args(2);
		args[0] = "-o";
		args[1] = "1";
	
		BOOST_CHECK_NO_THROW( opts.parse(args) );
		BOOST_CHECK_EQUAL( gMyFunctionValue, 1 );
	}
}

BOOST_AUTO_TEST_CASE( test_bind_option_mem_fun )
{
	MyObject o;

	woptions::Options opts;
	opts.option("-o","(value)","desc",woptions::bind_option_mem_fun(&o,&MyObject::SetValue));
	
	{
		std::vector<std::string> args(2);
		args[0] = "-o";
		args[1] = "1";
	
		BOOST_CHECK_NO_THROW( opts.parse(args) );
		BOOST_CHECK_EQUAL( o.value, 1 );
	}
}

BOOST_AUTO_TEST_CASE( test_bind_option_join )
{
	bool b1=false, b2=false;
	
	woptions::Options opts;
	opts.option("-o","","desc",
		woptions::bind_option_join(
		woptions::bind_option_value(b1,true),
		woptions::bind_option_value(b2,true)));
	
	std::vector<std::string> args(1);
	args[0] = "-o";
	
	BOOST_CHECK_NO_THROW( opts.parse(args) );
	BOOST_CHECK_EQUAL( b1, true );
	BOOST_CHECK_EQUAL( b2, true );
}

BOOST_AUTO_TEST_CASE( test_hide_option_default )
{
	int i = 1;
	BOOST_CHECK_EQUAL(
		woptions::bind_option_var(i).default_string(), 
		"1" );
	BOOST_CHECK_EQUAL(
		woptions::hide_option_default(woptions::bind_option_var(i)).default_string(), 
		"" );
}


